package titt.service.strategy;

import java.util.ArrayList;
import java.util.HashMap; 
import java.util.Map;

import titt.TITTValues;
import titt.error.NuderException;
import titt.head.request.MethodHead;

import titt.io.socket.TITTSocket;

import titt.service.ServicePackage;
import titt.service.content.NuderRequest;
import titt.service.content.NuderResponse;
import titt.service.os.ServiceObjectServer;

import titt.type.TypedObject;
import titt.type.Types;
import titt.util.ArrayUtil;

public class NuderStrategy implements TITTStrategy {

	private Map<Long, ServicePackage> packages = new HashMap<Long, ServicePackage>();

	public synchronized ServicePackage getPackage(long id) {
		return packages.get(id);
	}

	public String getID() {
		return "nuder";
	}

	@Override
	public void invokeAndRespond(MethodHead m, ServiceObjectServer sos, ServicePackage pack) {

		String packageID = pack.getPackageID();

		long id = Thread.currentThread().getId();

		addPackage(id, pack);

//		WRITE METHOD getInternalParams in MethodHead instead :)
//
//		TypedObject[] args = m.getParams();
//		
//		if(args.length > 0 && args[args.length - 1].getType().equals(NuderTypes.LISTENER)) {
//
//			String listener = args[args.length-1].getObject();
//			
//			TypedObject[] newargs = new TypedObject[args.length-1];
//			ArrayUtil.copyTo(args, 0, newargs, 0, newargs.length);
//			args = newargs;
//		}
		
		TypedObject[] postargs = {};
		
		if(m.getHTTPMethod() == TITTValues.POST)
			postargs = new TypedObject[]{new TypedObject(Types.toNative(NuderRequest.class), new NuderRequest(m, pack.getTITTSocket().getInputStream()))};
		
		TypedObject ret;
		int status = 200;

		try {
			ret = sos.getMethodInvoker().call(m.getMethodName(), ArrayUtil.combine(m.getParams(),postargs));
		}
		catch(Exception e) {

			try {
				throw e.getCause();
			}
			catch(NuderException ex) {
				ret = new TypedObject(Types.UNKNOWN, ex.getReponse());
				status = ex.getStatus();
			}
			catch(Throwable ex) {
				ret = new TypedObject(Types.STRING, ""+ex.getMessage());
				status = 418;
			}
		}

		removePackage(id);
		close(pack);

		if(ret.getObject() == null)
			ret = new TypedObject(Types.STRING, "null");

		TITTSocket ts = null;

		try {

			ts = sos.getServerProxy().sync(packageID);

//			NuderWriter nw = NuderFactory.createWriter(ts);
//			nw.writeValues(NuderResponse.wrap(ret.getObject(), status));

			NuderResponse nuderResp = null;
			
			if(ret.getObject() instanceof NuderResponse) 
				nuderResp = ret.getObject();
			else
				nuderResp = new NuderResponse(ret.getObject(), status);
			
			ts.getHeadWriter().writeHead(nuderResp.getHead());
			nuderResp.writeTo(ts.getOutputStream());
			ts.getOutputStream().flush();
			
			close(ts);
		}
		catch(Exception e) {
			close(ts);
		}
	}

	private synchronized void addPackage(long id, ServicePackage pack) {
		packages.put(id, pack);
	}

	private synchronized void removePackage(long id) {
		packages.remove(id);
	}

	private void close(TITTSocket ts) {
		try {
			if(ts != null && !ts.isClosed())
				ts.close();
		}
		catch(Exception e) {}
	}

	private void close(ServicePackage pack) {
		close(pack.getTITTSocket());	
	}

	//	@Override
	//	public String getStrategyID() {
	//		return "NUDER";
	//	}
	//
	//	@Override
	//	public void handleRequest(Object o, TITTSocket ts, MethodHead m, EncodingFacade ef, MethodInvoker inv) throws Exception {
	//
	//		Nuder s = o instanceof Nuder? (Nuder)o : null;
	//
	//		PushbackHeadReader hr = new PushbackHeadReader(IOFactory.createHeadReader(ts.getInputStream()));
	//		hr.unreadHead(m);
	//
	//		if(s != null)
	//			s.attachSocket(new SwapHeadSocket(ts, hr));
	//
	//		if(ServerProxy.get().isTITTMethod(m.getMethodName()))
	//			respondToTITT(o, m, ts, ef);
	//		else {
	//
	//			try {
	//				TypedObject to = inv.call(m.getMethodName(), m.getParams());
	//
	//				if(!to.getType().equals(Types.VOID))
	//					respond(to.getObject(), 200, ts);
	//			}
	//			catch(Exception ex) {
	//				try {
	//					throw ex.getCause();
	//				}
	//				catch(NuderException e) {
	//					respond(e.getReponse(), e.getStatus(), ts);
	//				}
	//				catch(Throwable e) {
	//					ts.getHeadWriter().writeHead(new ResponseHead(418, HeadFactory.EMPTY));	
	//				}			
	//			}
	//
	//		}
	//
	//		if(s != null)
	//			s.attachSocket(ts);
	//
	//	}
	//
	//	private void respondToTITT(Object o, MethodHead m, TITTSocket ts, EncodingFacade enc) throws Exception {
	//
	//		TypedObject[] args = m.getParams();
	//		if(m.getHTTPMethod() == TITTValues.POST) {
	//			POSTReader pr = new POSTReader(ts, enc, new FormHead(m));
	//			args = ArrayUtil.combine(args, pr.readValues());
	//		}
	//
	//		TypedObject ret = ServerProxy.get().callTITTMethod(o, m.getMethodName(), args);
	//
	//		ResponseWriter rw = new ResponseWriter(ts, enc, new ResponseHead(200, HeadFactory.EMPTY));
	//		rw.writeValues(ret);
	//	}
	//
	//	private void respond(Object ret, int status, TITTSocket ts) throws Exception {
	//		NuderWriter nw = NuderFactory.createWriter(ts);
	//
	//		NuderContent nc = NuderContent.wrap(ret, status);
	//		nw.writeValues(nc);
	////		System.out.println(ts.isClosed());
	//	}


}
